# coding=utf-8
from django.db import transaction
from rest_framework import serializers
from rest_framework.exceptions import ValidationError

from MSB_ERP.utils.get_inventory import get_inventory
from warehouse_info.models import PurchaseStorageModel, PurchaseStorageItemModel


class InStorageItemSerializer(serializers.ModelSerializer):
    # 注意：只有库存数据没有，那么可以增加一个属性
    cur_inventory = serializers.SerializerMethodField(read_only=True, label='在当前仓库中的库存')  # label在测试的时候会提示的中文名称

    class Meta:
        model = PurchaseStorageItemModel
        fields = '__all__'

    def get_cur_inventory(self, obj):
        # obj.goods.id拿到的是商品的ID
        result = get_inventory(goods_id=obj.goods.id, warechouse_id=obj.warehouse.id)
        return result if result else 0


class InStorageSerializer(serializers.ModelSerializer):
    '''
    入库单--反序列化器（用于新增和修改）和查询列表的序列化器（用于入库单列表）
    '''

    # 这个是PurchaseStorageItemModel的purchase_storage的反向属性名
    item_list = InStorageItemSerializer(many=True)

    # 商品信息：商品1 商品1的规格，商品2 商品2的规格...
    goods_info = serializers.SerializerMethodField(read_only=True, label='包括入库单中的每个商品信息')

    class Meta:
        model = PurchaseStorageModel
        fields = '__all__'

    def get_goods_info(self, obj):
        if obj.item_list.all():
            result = []
            for item in obj.item_list.all():
                # item.name返回的是商品名称
                # item.specification if item.specification else ''是三位换算符
                # ==> if item.specification 如果有这个属性的值的话就用这个属性的值item.specification
                # 判断成功的话结果放if前面，else的话就用空字符
                result.append(item.name + (item.specification if item.specification else ''))
            # 返回的是一个列表，列表的每一个值都是用逗号去隔开
            return ','.join(result)  # 把列表全部展开，每一值之间都用，隔开
        return ''  # 其他情况下就返回一个空的字符串

    # 同时插入入库单和入库单中货品项，必须重写create
    def create(self, validated_data):  # 这个不是新增单个对象而是新增多个对象
        item_list = validated_data.pop('item_list')  # 拿取数据

        with transaction.atomic(): # 数据库事务
            # 新增得到一个入库单，因为validated_data已经把item_list全部抽出来了，就剩入库单了
            in_storage = PurchaseStorageModel.objects.create(**validated_data) # 把剩下来的数据展开然后传值进去
            for item in item_list:
                # 只要是外键关系他传的都是ID来的
                # 入库的项目对象（在传其他字段item属性的时候，这里的'goods'传的是ID而已）
                psi = PurchaseStorageItemModel.objects.create(purchase_storage=in_storage, **item)
                # 把一些冗余的属性加进去（这里再拿goods的时候是把goods里面的属性再添加到别的表去）
                goods = item.get('goods')  # 拿到goods（他是一个对象）
                psi.specification = goods.specification
                psi.model_number = goods.model_number
                psi.number_code = goods.number_code
                psi.color = goods.color
                psi.category = goods.category
                psi.category_name = goods.category.name
                psi.units = goods.units
                psi.units_name = goods.units.basic_name

                psi.save()  # 如果数据库中有这个数据的话会自动的修改，没有的话他会帮你进行新增

        return in_storage

    # instance就是正在修改的用户单，validated_data修改请求参数
    def update(self, instance, validated_data):
        # 修改条件
        if instance.status != '0':
            raise ValidationError('入库单已经生效，不能进行修改')
        else:
            item_list = validated_data.pop('item_list')  # 请求参数中的新项目数据
            # 从数据库中拿取item_list的现有的数据
            old_list = instance.item_list.all()
            with transaction.atomic():
                if old_list.exists():  # 判断数据是否存在
                    # 删除旧的入库项目数据
                    old_list.delete()
                for item in item_list:
                    # 入库的项目对象
                    psi = PurchaseStorageItemModel.objects.create(purchase_storage=instance, **item)
                    # 把一些冗余的属性加进去
                    goods = item.get('goods')  # 拿到goods（他是一个对象）
                    psi.specification = goods.specification
                    psi.model_number = goods.model_number
                    psi.number_code = goods.number_code
                    psi.color = goods.color
                    psi.category = goods.category
                    psi.category_name = goods.category.name
                    psi.units = goods.units
                    psi.units_name = goods.units.basic_name

                    psi.save()  # 如果数据库中有这个数据的话会自动的修改，没有的话他会帮你进行新增
                result = super(InStorageSerializer, self).update(instance=instance, validated_data=validated_data)
            return result


class InStorageGetSerializer(serializers.ModelSerializer):
    '''
    仅仅用于查询单个入库的序列化器
    '''

    # 显示的列包括：仓库名称，货品编号，货品名称，规格，型号，颜色，库存，单位，入库数量，单价，金额，标注
    # 注意：以上只有库存数据在PurchaseStorageItemModel没有，这就是冗余字段多的好处
    # 这个是PurchaseStorageItemModel的purchase_storage的反向属性名
    item_list = InStorageItemSerializer(many=True)

    class Meta:
        model = PurchaseStorageModel
        fields = '__all__'
